using System;
using System.IO;
using System.Collections;
using System.Windows.Forms;

namespace PSTools
{
	public class IniParser
	{
		private Hashtable keyPairs = new Hashtable();
		private String iniFilePath;

		private struct SectionPair
		{
			public String Section;
			public String Key;
		}

		/// <summary>
		/// Opens the INI file at the given path and enumerates the values in the IniParser.
		/// </summary>
		/// <param name="iniPath">Full path to INI file.</param>
		public IniParser(String iniPath)
		{
			TextReader iniFile = null;
			String strLine = null;
			String currentRoot = null;
			String[] keyPair = null;

			iniFilePath = iniPath;

			if (File.Exists(iniPath))
			{
				try
				{
					iniFile = new StreamReader(iniPath);

					strLine = iniFile.ReadLine();

					while (strLine != null)
					{
						strLine = strLine.Trim();

						if (strLine != "")
						{
							if (strLine.StartsWith("[") && strLine.EndsWith("]"))
							{
								currentRoot = strLine.Substring(1, strLine.Length - 2);
							}
							else
							{
								keyPair = strLine.Split(new char[] { '=' }, 2);

								SectionPair sectionPair;
								String value = null;

								if (currentRoot == null)
									currentRoot = "ROOT";

								sectionPair.Section = currentRoot;
								sectionPair.Key = keyPair[0].Trim();

								if (keyPair.Length > 1)
									value = keyPair[1].Trim();

								keyPairs.Add(sectionPair, value);
							}
						}

						strLine = iniFile.ReadLine();
					}

				}
				catch (Exception ex)
				{
					throw ex;
				}
				finally
				{
					if (iniFile != null)
						iniFile.Close();
				}
			}
			else
				throw new FileNotFoundException("Unable to locate " + iniPath);

		}

		/// <summary>
		/// Returns the value for the given section, key pair.
		/// </summary>
		/// <param name="sectionName">Section name.</param>
		/// <param name="settingName">Key name.</param>
		public String GetSetting(String sectionName, String settingName)
		{
			SectionPair sectionPair;
			sectionPair.Section = sectionName;
			sectionPair.Key = settingName;

			return (String)keyPairs[sectionPair];
		}

		/// <summary>
		/// Enumerates all lines for given section.
		/// </summary>
		/// <param name="sectionName">Section to enum.</param>
		public String[] EnumSection(String sectionName)
		{
			ArrayList tmpArray = new ArrayList();

			foreach (SectionPair pair in keyPairs.Keys)
			{
				if (pair.Section == sectionName)
					tmpArray.Add(pair.Key);
			}

			return (String[])tmpArray.ToArray(typeof(String));
		}

		/// <summary>
		/// Enumerates all lines.
		/// </summary>
		public String[] EnumAllSections()
		{
			ArrayList tmpArray = new ArrayList();

			foreach (SectionPair pair in keyPairs.Keys)
			{
				tmpArray.Add(pair.Section);
			}

			return (String[])tmpArray.ToArray(typeof(String));
		}

		public String[] EnumAllKeys()
		{
			ArrayList tmpArray = new ArrayList();

			foreach (SectionPair pair in keyPairs)
			{
				tmpArray.Add(pair.Section);
			}

			return (String[])tmpArray.ToArray(typeof(String));
		}

		/// <summary>
		/// Adds or replaces a setting to the table to be saved.
		/// </summary>
		/// <param name="sectionName">Section to add under.</param>
		/// <param name="settingName">Key name to add.</param>
		/// <param name="settingValue">Value of key.</param>
		public void AddSetting(String sectionName, String settingName, String settingValue)
		{
			SectionPair sectionPair;
			sectionPair.Section = sectionName;
			sectionPair.Key = settingName;

			if (keyPairs.ContainsKey(sectionPair))
				keyPairs.Remove(sectionPair);

			keyPairs.Add(sectionPair, settingValue);
			
		}

		/// <summary>
		/// Adds or replaces a setting to the table to be saved with a null value.
		/// </summary>
		/// <param name="sectionName">Section to add under.</param>
		/// <param name="settingName">Key name to add.</param>
		public void AddSetting(String sectionName, String settingName)
		{
			AddSetting(sectionName, settingName, null);
		}

		/// <summary>
		/// Remove a setting.
		/// </summary>
		/// <param name="sectionName">Section to add under.</param>
		/// <param name="settingName">Key name to add.</param>
		public void DeleteSetting(String sectionName, String settingName)
		{
			SectionPair sectionPair;
			sectionPair.Section = sectionName;
			sectionPair.Key = settingName;

			if (keyPairs.ContainsKey(sectionPair))
				keyPairs.Remove(sectionPair);
		}

		/// <summary>
		/// Save settings to new file.
		/// </summary>
		/// <param name="newFilePath">New file path.</param>
		public void SaveSettings(String newFilePath)
		{
			ArrayList sections = new ArrayList();
			ArrayList __values = new ArrayList();
			String tmpValue = "";
			String strToSave = "";

			foreach (SectionPair sectionPair in keyPairs.Keys)
			{
				if (!sections.Contains(sectionPair.Section))
					sections.Add(sectionPair.Section);
			}

			sections.Sort();

			foreach (String section in sections)
			{
				strToSave += ("[" + section + "]\r\n");

				__values = new ArrayList();

				foreach (SectionPair sectionPair in keyPairs.Keys)
				{
					if (sectionPair.Section == section)
					{
						tmpValue = (String)keyPairs[sectionPair];

						if (tmpValue != null)
						{
							int __int1 = (sectionPair.Key.ToString().Length >= 15) ? 1:0;

							int __int2 = (__int1 > 0) ? sectionPair.Key.ToString().Length - 15: 0;

							//double __dbl = (double)sectionPair.Key.ToString().Length;
							tmpValue = new string('\t', (int)(6 - Math.Floor((double)sectionPair.Key.ToString().Length / 8))) + "= " + tmpValue;
							//tmpValue = new string('\t', (int)(4 - __int1 - Math.Floor((double)__int2 / 8))) + "= " + tmpValue;
							//MessageBox.Show(Math.Floor(__dbl / 15).ToString());
						}
							

						//strToSave += (sectionPair.Key + tmpValue + "\r\n");
						__values.Add(sectionPair.Key + tmpValue);
						
					}
				}

				__values.Sort();

				foreach (String __item in __values)
				{
					strToSave += (__item + "\r\n");
				}

				strToSave += "\r\n";
			}

			try
			{
				TextWriter tw = new StreamWriter(newFilePath);
				tw.Write(strToSave);
				tw.Close();
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		/// <summary>
		/// Save settings back to ini file.
		/// </summary>
		public void SaveSettings()
		{
			SaveSettings(iniFilePath);
		}
	}
}
